<!doctype html>
<html>
<head>
<title>01b - Gravity Collision Test</title>
<style>
body {
	background-color: grey;
}
canvas {
	background-color: white;
}
</style>
<script src="../libs/jquery.min.js"></script>
<script src="../libs/raf_polyfill.js"></script>
<script src="../libs/gl-matrix-min.js"></script>
<script src="../libs/webgl-debug.js"></script>
<script src="../libs/vector3.js"></script>
<script src="../libs/sphere_mesh.js"></script>
<script src="../libs/plane_mesh.js"></script>
<script src="../libs/SphereObject.js"></script>
<script id="shader-vs" type="x-shader/x-vertex">
	uniform mat4 uMVMatrix;
	uniform mat4 uPMatrix;

	attribute vec3 aVertexPosition;
	attribute vec4 aVertexColor;
	attribute vec3 aVertexNormal;

	varying highp vec4 vColor;
	varying highp vec3 vPosition;
	varying highp vec3 N;

	void main(void) {
		gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
        
        vColor = aVertexColor;
        vPosition = aVertexPosition;
		N = aVertexNormal; 		
	}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
	uniform highp mat3 uNormalMatrix;
	uniform highp mat4 uMVMatrix;
	uniform highp mat4 uPMatrix;

	varying highp vec4 vColor;
	varying highp vec3 vPosition;
	varying highp vec3 N;

	void main(void) {
        highp vec3 pointLightPosition = vec3(-1.0,3.0,1.0);

        highp vec3 pointLightDirection = vec3(pointLightPosition.xyz - vPosition.xyz);

		highp mat4 mvp = uPMatrix * uMVMatrix;

        highp vec3 L = vec3(mvp * vec4(pointLightDirection, 1.0));
		highp vec3 V = -vec3(mvp * vec4(vPosition,1.0));

   		highp vec3 l = normalize(L);
    	highp vec3 n = normalize(uNormalMatrix * N);
    	highp vec3 v = normalize(V);
		
		highp vec3 R = reflect(l, n);

		highp float diffuseLambert = dot(l,n);
		highp float Roughness = 1.0;
		highp float AmbientIntensity = 0.3;
		highp vec3 DiffuseLightIntensity = vec3(0.9, 0.9, 0.9);
		highp float SpecularIntensity = 0.5;
		highp float shininess = 128.0;

		highp float specular = pow( max(0.0,dot(R,v)), shininess);

		highp vec3 AmbientColour = vec3(0.1, 0.1, 0.1);
		highp vec3 DiffuseMaterialColour = vColor.xyz;
		highp vec3 SpecularColour = vec3(1.0, 1.0, 1.0);
    
	    gl_FragColor = vec4(AmbientColour*AmbientIntensity + 
                        diffuseLambert * DiffuseMaterialColour*DiffuseLightIntensity +
                        SpecularColour * specular*SpecularIntensity, vColor.a);
	}
</script>
<script>
			var gl = null,
				canvas = null,
				glProgram = null,
				fragmentShader = null,
				vertexShader = null;
				
			var vertexPositionAttribute = null,
				vertexNormalAttribute = null,
				vertexColorAttribute = null,
				trianglesVerticeBuffers = [],
				trianglesNormalBuffers = [],
				trianglesColorBuffers = [],
				vertexIndexBuffers = [];

			var sceneElements = []; 
			var INITIAL_HEIGHT_TRANSLATION_OF_SPHERES  = 5.0;
			var GROUND_Y = -1.0;

			var mvMatrix = mat4.create(),
				pMatrix = mat4.create(),
				normalMatrix = mat3.create();

			var paused = false;

			$(document).keyup(function(evt){
                switch(evt.keyCode){
	                case 80: //'p'
	                    paused =!paused;
	                    break;	                
	                default:
	                	break;    
	            }    	
		    });	  

			function initWebGL()
			{
				canvas = document.getElementById("my-canvas");  
				try{
					gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");					
				}catch(e){
				}
								
				if(gl)
				{
					gl = WebGLDebugUtils.makeDebugContext(gl);

					initShaders();
					setupSphereMesh(0, {
											"translation": [-1.0, -0.75, 0.0], 
											"color": [1.0, 0.0, 0.0, 1.0],
										}
									);
					setupSphereMesh(1, {
											"translation": [0.0, 0.0, 1.0], 
											"color": [0.0, 1.0, 0.0, 1.0]
										}
					);
					setupSphereMesh(2, {
											"translation": [1.0, 0.25, -1.0], 
											"color": [1.0, 1.0, 0.0, 1.0]
										}
					);
					setupPlaneMesh(3, {	"translation": [0.0, GROUND_Y, 0.0]} );
					
					sceneElements.push(new SphereObject( {"vbo_index": 0} ) );
					sceneElements.push(new SphereObject( {"vbo_index": 1} ) );
					sceneElements.push(new SphereObject( {"vbo_index": 2} ) );
					getMatrixUniforms();					

					vertexPositionAttribute = gl.getAttribLocation(glProgram, "aVertexPosition");
					vertexColorAttribute = gl.getAttribLocation(glProgram, "aVertexColor");
					vertexNormalAttribute = gl.getAttribLocation(glProgram, "aVertexNormal");
	                gl.enableVertexAttribArray(vertexPositionAttribute);
	                gl.enableVertexAttribArray(vertexColorAttribute);
	                gl.enableVertexAttribArray(vertexNormalAttribute);
    			    
    			    gl.viewport(0, 0, canvas.width, canvas.height);
					mat4.perspective(45, canvas.width / canvas.height, 0.1, 100.0, pMatrix);
					gl.uniformMatrix4fv(glProgram.pMatrixUniform, false, pMatrix);
					
					(function animLoop(){
						if( !paused ){	
							setupWebGL();
							drawScene(); 
						}
						requestAnimationFrame(animLoop, canvas);
					})();
				}else{	
					alert(  "Error: Your browser does not appear to support WebGL.");
				}
			}
			
			function setupWebGL()
			{
				//set the clear color to a shade of green
				gl.clearColor(0.5, 0.5, 0.5, 1.0); 	
				gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 	
				gl.enable(gl.DEPTH_TEST);
			}
			
			function initShaders()
			{
				//get shader sources with jQuery Ajax
				$.ajax({
				    async: false,
				    url: './01_gravity.vs',
				    success: function (data) {
				        vs_source = data.firstChild.textContent;
				    },
				    dataType: 'xml'
				});

				$.ajax({
				    async: false,
				    url: './01_gravity.fs',
				    success: function (data) {
				        fs_source = data.firstChild.textContent;
				    },
				    dataType: 'xml'
				});

				//compile shaders	
                vertexShader = makeShader(vs_source, gl.VERTEX_SHADER);
				fragmentShader = makeShader(fs_source, gl.FRAGMENT_SHADER);
				
				//create program
				glProgram = gl.createProgram();
				
				//attach and link shaders to the program
                gl.attachShader(glProgram, vertexShader);
                gl.attachShader(glProgram, fragmentShader);
                gl.linkProgram(glProgram);

                if (!gl.getProgramParameter(glProgram, gl.LINK_STATUS)) {
                    alert("Unable to initialize the shader program.");
                }
				
				//use program
				gl.useProgram(glProgram);
			}
			
			function makeShader(src, type)
			{
				//compile the vertex shader
				var shader = gl.createShader(type);
                gl.shaderSource(shader, src);
                gl.compileShader(shader);

                if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
                    alert("Error compiling shader: " + gl.getShaderInfoLog(shader));
                }
				return shader;
			}

			function searchForObject(arr, index)
			{
				for(var i in arr)
				{
					if(arr[i].vbo_index == index)
					{
						return i;
					}	
				}
				return -1;
			}
			
			function drawScene()
			{
		
				for(var i=0; i < vertexIndexBuffers.length; ++i)
				{

					mat4.identity(mvMatrix);
					mat4.translate(mvMatrix, [0.0, -1.0, -15.5]);              		

					var n = searchForObject(sceneElements, i);
					if( n != -1)
					{
						if( ( INITIAL_HEIGHT_TRANSLATION_OF_SPHERES - (sceneElements[n].position.y + sceneElements[n].radius) ) > GROUND_Y)
						{
							sceneElements[n].position.y += 0.1; 
						}

						mat4.translate(mvMatrix, [sceneElements[n].position.x, 
												INITIAL_HEIGHT_TRANSLATION_OF_SPHERES  - sceneElements[n].position.y, 
												sceneElements[n].position.z]);             
					}
	    			mat4.toInverseMat3(mvMatrix, normalMatrix);
		   			mat3.transpose(normalMatrix);
					setMatrixUniforms();

					gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffers[i]);
					gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);

					gl.bindBuffer(gl.ARRAY_BUFFER, trianglesColorBuffers[i]);
					gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);

					gl.bindBuffer(gl.ARRAY_BUFFER, trianglesNormalBuffers[i]);
					gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);
					
					gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffers[i]);
					gl.drawElements(gl.TRIANGLES, vertexIndexBuffers[i].numItems, gl.UNSIGNED_SHORT, 0);
				}
			}
			
			function getMatrixUniforms(){
                glProgram.pMatrixUniform = gl.getUniformLocation(glProgram, "uPMatrix");
                glProgram.mvMatrixUniform = gl.getUniformLocation(glProgram, "uMVMatrix");          
                glProgram.normalMatrixUniform = gl.getUniformLocation(glProgram, "uNormalMatrix");          
            }
			
			function setMatrixUniforms() {       
                gl.uniformMatrix4fv(glProgram.mvMatrixUniform, false, mvMatrix);
                gl.uniformMatrix3fv(glProgram.normalMatrixUniform, false, normalMatrix);
            }   
		</script>
</head>
<body onload="initWebGL()">
<canvas id="my-canvas" width="500" height="500"> Your browser does not support the HTML5 canvas element. </canvas>
</body>
</html>
